package task

import (
	"encoding/json"
	"fmt"
	"sieve_engine/utils"
	"strings"
	"sync"
	"time"
)

type Info struct {
	Progress
	Id            string    `json:"id" redis:"id"`
	TaskCount     int       `json:"task_count" redis:"task_count"` //任务数------->后台传参
	Country       string    `json:"country" redis:"country"`       //国家------->后台传参
	Operator      string    `json:"operator" redis:"operator"`     //业务类型 filter=ws,fb=facebook,active=ws_active,ins=ins,linkedin=linkedin,amazon=amazon
	ElapsedTime   string    `json:"elapsed_time" redis:"elapsed_time"`
	SrcListKey    string    `json:"src_list_key" redis:"src_list_key"`
	ResultListKey string    `json:"result_list_key" redis:"result_list_key"`
	AreaCode      string    `json:"area" redis:"area"` //代码------->后台传参
	CreateAt      time.Time `json:"create_at" redis:"create_at"`
	UpdateAt      time.Time `json:"update_at" redis:"update_at"`
}

func (t Info) String() string {

	b, _ := json.Marshal(t)
	return string(b)
}

type Progress struct {
	State       Status `json:"state"  redis:"state"`              // 当前任务的最新状态
	TaskCount   int64  `json:"task_count" redis:"task_count"`     // 筛有效的数量
	ValidCount  int64  `json:"valid_count" redis:"valid_count"`   // 筛有效的数量
	FinishCount int64  `json:"finish_count" redis:"finish_count"` // 已经完成的筛选的数量
}

func (t *Progress) string() string {
	b, _ := json.Marshal(t)
	return string(b)
}

func (t *Progress) increase(tt Progress) {
	t.State = tt.State
	t.FinishCount += tt.FinishCount
	t.ValidCount += tt.ValidCount
	return
}

func (t *Progress) MarshalBinary() (data []byte, err error) {

	tt := t.string()
	return []byte(tt), nil
}

type Result struct {
	locker          sync.Mutex
	fCallBack       func(interface{}, *Result)
	fNotifyCallBack func(*Result) bool
	notify          chan struct{}
	Progress
	serviceExecutor interface{}
	AllFinishCount  int64
	NotifyCount     int64
	unusualFinished bool
	results         []interface{}
	phones          []string
}

func NewTaskResult(s interface{}, phones []string, fCallBack func(interface{}, *Result), fNotifyCallBack func(*Result) bool) *Result {
	return &Result{
		Progress: Progress{
			State:     StatusRun,
			TaskCount: int64(len(phones)),
		},
		serviceExecutor: s,
		fCallBack:       fCallBack,
		phones:          phones,
		fNotifyCallBack: fNotifyCallBack,
	}
}

func (t *Result) WithTaskState(state Status) *Result {

	t.Progress.State = state
	return t
}

func (t *Result) WithTaskProgress(progress Progress) *Result {

	t.Progress = progress
	return t
}

func (t *Result) WithPhones(phones []string) *Result {

	t.phones = phones
	return t
}

func (t *Result) WithResults(results []interface{}) *Result {

	t.results = results
	return t
}

func (t *Result) Results() []interface{} {
	return t.results
}

func (t *Result) Phones() []string {

	return t.phones
}

func (t *Result) AppendResult(result interface{}, valid bool) *Result {

	t.locker.Lock()
	defer t.locker.Unlock()

	r := result
	if valid {
		r = fmt.Sprintf("%v>in", result)
		t.ValidCount = t.ValidCount + 1
	}
	t.results = append(t.results, r)
	t.FinishCount = t.FinishCount + 1
	t.AllFinishCount = t.AllFinishCount + 1
	if t.fNotifyCallBack != nil && t.fCallBack != nil {
		if t.fNotifyCallBack(t) {

			r := t.Clone()
			r.NotifyCount = t.FinishCount
			t.ValidCount = 0
			t.FinishCount = 0
			t.results = []interface{}{}

			t.fCallBack(t.serviceExecutor, r)
		}
	}
	return t
}

func (t *Result) FastFinish() {

	t.locker.Lock()
	defer t.locker.Unlock()
	r := &Result{}
	if len(t.results) != 0 {
		r = t.Clone()
	}

	if !t.unusualFinished {

		t.unusualFinished = true
		// 任务被终止，那么将剩余数量标记一下
		r.NotifyCount = t.TaskCount - t.AllFinishCount + t.FinishCount
		t.ValidCount = 0
		t.FinishCount = 0
		t.results = []interface{}{}

		t.fCallBack(t.serviceExecutor, r)
	}
	return
}

func (t *Result) Finished() bool {

	return t.AllFinishCount == int64(len(t.phones))
}

func (t *Result) SplitResult(chunkSize int) [][]interface{} {

	return utils.ChunkSliceInterface(t.results, chunkSize)
}

func (t *Result) SplitPhones(chunkSize int) [][]string {

	return utils.ChunkSliceString(t.phones, chunkSize)
}

func (t *Result) Clone() *Result {

	var (
		results = make([]interface{}, len(t.results))
		phones  = make([]string, len(t.results))
	)

	for i, v := range t.results {
		results[i] = v

		vv := fmt.Sprintf("%v", v)
		if strings.Contains(vv, ">in") {

			vv = vv[0 : len(vv)-len(">in")]
		}

		phones[i] = vv
	}

	return (&Result{}).WithResults(results).WithTaskProgress(t.Progress).WithPhones(phones)
}

func (t *Result) Clear() {

	t.results = t.results[0:]
	return
}

func (t *Result) Increase(tt *Result) {

	t.Progress.increase(tt.Progress)
	t.results = append(t.results, tt.results...)
	return
}

type Status string

func (ts Status) MarshalBinary() (data []byte, err error) {

	return []byte(ts), nil
}

const (
	StatusInit      Status = "init"
	StatusRun       Status = "run"
	StatusFinish    Status = "finish"
	StatusPause     Status = "pause"
	StatusTerminate Status = "terminate"
)
